using System;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;

namespace MintAnimation.Core
{

    public class MintTween : IDisposable
    {

        public MintTween(Action<float> OnUpdate, float startValue, float endValue, MintTweenOptions mintTweenOption = null)
        {
            IMintChannel mintChannel = new MintChannelFloat(OnUpdate, startValue, endValue);
            this.Init(mintChannel, mintTweenOption);
        }

        public MintTween(Action<Vector3> OnUpdate, Vector3 startValue, Vector3 endValue, MintTweenOptions mintTweenOption = null)
        {
            IMintChannel mintChannel = new MintChannelVector3(OnUpdate, startValue, endValue);
            this.Init(mintChannel, mintTweenOption);
        }

        public MintTween(Action<Color> OnUpdate, Color startValue, Color endValue, MintTweenOptions mintTweenOption = null)
        {
            IMintChannel mintChannel = new MintChannelColor(OnUpdate, startValue, endValue);
            this.Init(mintChannel, mintTweenOption);
        }

        public MintTween(IMintChannel mintMintChannel, MintTweenOptions mintTweenOption = null) { this.Init(mintMintChannel, mintTweenOption); }


        private void Init(IMintChannel mintMintChannel, MintTweenOptions mintTweenOption = null)
        {
            this.UpdateOption(mintTweenOption);
            this._updaterType = this._tweenOption.UpdaterTypeEnum;
            this._mintChannel = mintMintChannel;
            this.register();
            this._isPause  = true;
            this.IsPlaying = false;
        }

        public event Action OnComplete;
        public bool IsPause
        {
            get => this._isPause;
            private set
            {
                if (this._isPause != value)
                {
                    if (value)
                        MintDriveComponentSinge.Instance.RemoveCount(this._updaterType);
                    else
                        MintDriveComponentSinge.Instance.AddCount(this._updaterType);
                }

                this._isPause = value;
            }
        }

        public MintTweenOptions TweenOption
        {
            get => this._tweenOption;
        }

        public bool IsPlaying { get; private set; }

        private bool             _isEnd;
        private bool             _isPause;
        private MintTweenOptions _tweenOption;
        private IMintChannel     _mintChannel;
        private float            _nowTime;
        private int              _nowLoopCount;
        private bool             _isKill;
        private UpdaterTypeEnum  _updaterType;
        private float            _progressTime;
        private float            _progress;


        /// <summary>
        /// 播放动画/从指定时间开始播放
        /// </summary>
        /// <param name="startTime"></param>
        public void Start(float startTime = 0)
        {
            this._isEnd        = false;
            this._nowTime      = Mathf.Clamp(startTime, 0, this._tweenOption.Duration);
            this._nowLoopCount = 0;
            this.IsPause       = false;
            this.IsPlaying     = true;
            this.UpdateTweenControl();
            this.UpdateProcess();
        }

        public void Pause()
        {
            if (!this.IsPlaying)
                return;
            if (!this.IsPause)
            {
                this.IsPause = true;
            }
        }

        public void Resume()
        {
            if (!this.IsPlaying)
                return;
            if (this.IsPause)
            {
                this.IsPause = false;
            }
        }

        /// <summary>
        /// 结束动画，并跳转至末尾
        /// </summary>
        public void End()
        {
            if (this._isKill || this._isEnd)
                return;
            this._nowTime = this._tweenOption.Duration;
            if (this._tweenOption.IsBack)
            {
                this._progressTime = this._tweenOption.IsFlip ? this._tweenOption.Duration : 0;
                this._progress     = this._tweenOption.IsFlip ? 1 : 0;
            }
            else
            {
                this._progressTime = this._tweenOption.IsFlip ? 0 : this._tweenOption.Duration;
                this._progress     = this._tweenOption.IsFlip ? 0 : 1;
            }

            this._mintChannel.OnProcessUpdate(this.GetTweenProgress());
            this._isEnd = true;
            this.OnCompleteAnim();
        }

        /// <summary>
        /// 立即中止并Kill当前动画驱动，销毁后无法继续使用
        /// </summary>
        public void Kill()
        {
            this._isPause     = true;
            this._tweenOption = null;
            this.OnComplete   = null;
            this.Dispose();
        }

        /// <summary>
        /// 获取当前播放时间的进度
        /// </summary>
        /// <returns></returns>
        public float GetTimeProgress() { return this._progressTime; }

        /// <summary>
        /// 获取当前从startValue 到 endValue 之间的进度
        /// </summary>
        /// <returns></returns>
        public float GetTweenProgress()
        {
            if (this._tweenOption.IsCustomEase)
            {
                return this._tweenOption.TimeCurve.Evaluate(this._progressTime / this._tweenOption.Duration);
            }
            else
            {
                return this._progress;
            }
        }

        /// <summary>
        /// 更新动画配置信息，且重置播放进度
        /// </summary>
        public void UpdateOption(MintTweenOptions tweenOptions)
        {
            if (tweenOptions == null)
                tweenOptions = new MintTweenOptions();
            this._tweenOption = tweenOptions;
            this.reset();
        }

        private void reset()
        {
            this._nowLoopCount = 0;
            this._progressTime = 0;
            this._progress     = 0;
            this._nowTime      = 0;
        }

        /// <summary>
        /// 动画进度驱动，用于计算下一帧进度数据，由驱动器调用
        /// </summary>
        internal void UpdateTweenControl()
        {
            if (this._nowTime > this._tweenOption.Duration)
                this._nowTime = this._tweenOption.Duration;
            float progressTime = this._nowTime;
            float progress     = 0f;
            float backTime     = this._tweenOption.Duration / 2f;
            if (this._tweenOption.IsBack)
            {
                if (progressTime <= backTime)
                    progressTime = progressTime * 2;
                else
                    progressTime = this._tweenOption.Duration - ((progressTime - backTime) * 2);
            }

            progressTime = this._tweenOption.IsFlip ? this._tweenOption.Duration - progressTime : progressTime;
            if (!this._tweenOption.IsCustomEase)
            {
                progress = MintEaseAction.GetEaseAction(this._tweenOption.EaseType, progressTime / this._tweenOption.Duration);
            }

            this._progressTime = progressTime;
            this._progress     = progress;
        }

        /// <summary>
        /// 动画进度驱动，用于执行下一帧数据，由驱动器调用
        /// </summary>
        /// <param name="deltaTime"></param>
        internal void OnLastControl(float deltaTime)
        {
            if (this._nowTime >= this._tweenOption.Duration)
            {
                this._nowTime = this._tweenOption.Duration;
                this._nowLoopCount++;
                if (this._tweenOption.IsLoop)
                {
                    if (this._tweenOption.LoopCount == -1 || this._nowLoopCount < this._tweenOption.LoopCount)
                    {
                        this._nowTime = 0;
                        this.UpdateProcess();
                        return;
                    }
                }

                this._isEnd = true;
                this.UpdateProcess();
                // //播放到最后一帧
                return;
            }

            this._nowTime += deltaTime;
            this.UpdateProcess();
        }

        /// <summary>
        /// 将计算的数据通知给channel做下一步处理
        /// </summary>
        internal void UpdateProcess()
        {
            this._mintChannel.OnProcessUpdate(this.GetTweenProgress());
            if (this._isEnd)
                this.OnCompleteAnim();
        }

        internal void OnCompleteAnim()
        {
            this.IsPlaying = false;
            this.IsPause   = true;
            this.OnComplete?.Invoke();
        }

        private void register()   { MintDriveComponentSinge.Instance.AddDriveAction(this, this._updaterType); }
        private void unregister() { MintDriveComponentSinge.Instance.RemoveDriveAction(this, this._updaterType); }

        public void Dispose()
        {
            if (!this._isKill)
            {
                this._isKill = true;
                this.unregister();
            }
        }

    }
}